Skip to content

10: Notices queue - #10

Open
nikolaystrikhar wants to merge 3 commits into
09-loader-resolvefrom
10-notices-queue
Open

10: Notices queue#10
nikolaystrikhar wants to merge 3 commits into
09-loader-resolvefrom
10-notices-queue

Conversation

@nikolaystrikhar

@nikolaystrikhar nikolaystrikhar commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Adds the notice queue and its interface — merge, conflict and dependency notices — plus Loader::notices(). Lands before the load path and the resolver because both call into it.

Stacked on #9.

  • The queue is an option, not a transient. With an object cache present set_transient() returns without touching the database, so wp_cache_flush() destroys the queue — and the merge notice is raised once, never re-queued. The Global Constraint that specified a transient is amended.
  • Multisite uses network options. deactivate_plugins() is network-wide, but a per-site transient files the explanation in whichever blog served the request.
  • render() checks activate_plugins first. Rendering deletes the queue, so any logged-in user reaching wp-admin could consume the administrator's only warning.
  • Wired to all_admin_notices. Core dispatches the three notice hooks as exclusive branches, so a superadmin in the network admin would never see the queue render.
  • Entries are keyed "{$slug}:{$type}". One sub-plugin can earn several notice types in one request; keying by slug drops all but one.

Verify: slic run unit — 125 tests, 186 assertions. --env multisite green, 1 deliberate skip. composer test:analysis[OK] No errors.

Not covered: concurrent read-modify-write on the queue can lose a notice.

Three defects, each of which loses the one warning a site owner gets that
their plugin was deactivated.

Storage was a transient. Verified in core: set_transient() short-circuits
to wp_cache_set() and never touches the database when an external object
cache is present, so on a Redis or Memcached site the queue lived only in
the cache -- where wp_cache_flush(), which deploy scripts and every purge
button call, destroys it. The merge notice is raised once and never
re-queued. It is an option now.

The queue was per-site while the deactivation is network-wide. The resolver
passes $network_wide to deactivate_plugins(), removing the plugin from every
site, but the explanation landed in whichever site's options table served
the request. On a fifty-site network the superadmin would never find it.
Multisite uses network options now.

render() consumes the queue and had no capability check, and it is wired to
a hook that fires for anyone who can reach wp-admin. A subscriber loading
profile.php silently swallowed the notice, and nothing re-queues it. It
checks activate_plugins first, which on multisite correctly resolves to
superadmins.

Also drop non-string entries instead of printing them, expose
option_name() so a host can render the same queue without replacing the
implementation, and cover the corrupted-queue, capability, cache-flush and
missing-prefix paths.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant